package linc.fun.openai.controller;

import cn.hutool.core.util.RandomUtil;
import com.google.common.collect.Lists;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import linc.fun.openai.config.code.EmailConfig;
import linc.fun.openai.config.exchange.ExchangeConfig;
import linc.fun.openai.constants.RabbitKeyConstants;
import linc.fun.openai.domain.dto.mq.StreamMessage;
import linc.fun.openai.domain.entity.chat.ChatExchangeDO;
import linc.fun.openai.domain.entity.chat.ChatProductDO;
import linc.fun.openai.domain.entity.chat.ChatUserDO;
import linc.fun.openai.domain.vo.response.R;
import linc.fun.openai.enums.EnableDisableStatusEnum;
import linc.fun.openai.enums.LogicDeleteEnum;
import linc.fun.openai.exception.BizException;
import linc.fun.openai.service.ChatExchangeService;
import linc.fun.openai.service.ChatProductService;
import linc.fun.openai.util.ExchangeCodeUtil;
import linc.fun.openai.util.IdGenerator;
import linc.fun.openai.util.ObjectMapperUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author yqlin
 * @date 2023/5/10 17:01
 * @description
 */
@Slf4j
@RestController
@RequestMapping("/api/test")
public class TestController {
    @Resource
    private StreamBridge streamBridge;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private IdGenerator idGenerator;
    @Resource
    private HttpServletResponse response;

    @Resource
    private EmailConfig emailConfig;

    @Operation(summary = "邮件验证回调")
    @GetMapping("/redirect")
    public void verifyEmailCode(@Parameter(description = "邮箱验证码") @RequestParam("code") String code) throws IOException {
        try {
            if (Objects.equals(code, "3")) {
                response.sendRedirect(emailConfig.getVerificationResponseUrl() + "?success=true");
            }
            throw BizException.CODE_NOT_EXIST_OR_EXPIRED;
        } catch (Exception e) {
            log.error("邮件回调异常: ", e);
            response.sendRedirect(emailConfig.getVerificationResponseUrl() + "?success=false&error_message=" + URLEncoder.encode(e.getMessage(), StandardCharsets.UTF_8));
        }

    }

    @GetMapping("sendMessage")
    public R<Void> testSendMessage() {
        ChatUserDO user = new ChatUserDO();
        user.setId(1L);
        user.setNickname("a");
        StreamMessage streamMessage = new StreamMessage();
        streamMessage.setMessageId(idGenerator.getIdStr());
        streamMessage.setMessageText(ObjectMapperUtil.toJson(user));
        log.info("发送时间:{}, 生产者发送消息:{}", new Date(), streamMessage);
        // 注意 MessageBuilder.withPayload 如果直接放对象实体,
        // 在 send 时, 对象实体转 byte 数组会造成数据丢失,
        // 怀疑是序列化的问题(只验证过问题, 还没找解决方式, 后续会继续排查)
        Message<String> message = MessageBuilder.withPayload(ObjectMapperUtil.toJson(streamMessage)).build();
        streamBridge.send(RabbitKeyConstants.CHAT_ORDER_DLQ_BINDING_NAME, message);
        return R.success();
    }

    @GetMapping("sendDelayMessage1")
    public R<Void> testSendDelayMessage1() {
        ChatUserDO user = new ChatUserDO();
        user.setId(1L);
        user.setNickname("a");
        log.info("发送时间:{}, 生产者发送消息:{}", new Date(), user);
        rabbitTemplate.convertAndSend(RabbitKeyConstants.CHAT_ORDER_DLQ_EXCHANGE, "#", ObjectMapperUtil.toJson(ObjectMapperUtil.toJson(user)), msg -> {
            MessageProperties messageProperties = msg.getMessageProperties();
            messageProperties.setDelay(5 * 1000);
            return msg;
        });
        return R.success();
    }


    @GetMapping("sendDelayMessage2")
    public R<Void> testSendDelayMessage() {
        ChatUserDO user = new ChatUserDO();
        user.setId(1L);
        user.setNickname("a");
        streamBridge.send(RabbitKeyConstants.CHAT_ORDER_DLQ_BINDING_NAME, MessageBuilder.withPayload(ObjectMapperUtil.toJson(user))
                .setHeader(RabbitKeyConstants.RABBIT_STREAM_X_DELAY, 5 * 1000)
                .build());
        log.info("发送延迟消息成功");
        return R.success();
    }

    @Resource
    private ChatExchangeService chatExchangeService;
    @Resource
    private ChatProductService chatProductService;

    @Resource
    private ExchangeConfig exchangeConfig;

    @GetMapping("generateExchange")
    public R<List<String>> generateExchange(Long productId) {
        ChatProductDO one = chatProductService.getById(productId);
        if (Objects.nonNull(one)) {
            List<ChatExchangeDO> exchanges = Lists.newArrayList();
            for (int i = 0; i < one.getStock(); i++) {
                String code = ExchangeCodeUtil.create((byte) RandomUtil.randomInt(exchangeConfig.getGroupIdStart(),
                                exchangeConfig.getGroupIdEnd())
                        , exchangeConfig.getCodeLength(), exchangeConfig.getSecret());
                ChatExchangeDO exchange = new ChatExchangeDO();
                exchange.setId(idGenerator.getId());
                exchange.setProductId(productId);
                exchange.setName(one.getName());
                exchange.setCode(code);
                exchange.setRewardUseTimes(one.getRewardUseTimes());
                exchange.setPrice(one.getPrice());
                exchange.setIsUsed(false);
                exchange.setStatus(EnableDisableStatusEnum.ENABLE);
                exchange.setIsDeleted(LogicDeleteEnum.NORMAL);
                exchange.setCreateTime(LocalDateTime.now());
                exchange.setUpdateTime(LocalDateTime.now());
                ExchangeCodeUtil.verifyCode(code, exchangeConfig.getCodeLength(), exchangeConfig.getSecret());
                exchanges.add(exchange);
            }
            chatExchangeService.saveBatch(exchanges);
        }
        return R.success();
    }
}
